package com.atguigu.product.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.constant.ProductConstant;
import com.atguigu.common.to.es.SkuEsModel;
import com.atguigu.common.to.es.SkuHasStockVo;
import com.atguigu.common.utils.R;
import com.atguigu.product.entity.*;
import com.atguigu.product.feign.SearchFeignService;
import com.atguigu.product.feign.WareFeignService;
import com.atguigu.product.service.*;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.product.dao.SpuInfoDao;

import javax.annotation.Resource;

@EnableFeignClients(basePackages = "com.atguigu.product.feign")
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

  @Resource
  SkuInfoService skuInfoService;

  @Resource
  BrandService brandService;

  @Resource
  CategoryService categoryService;

  @Resource
  ProductAttrValueService productAttrValueService;

  @Resource
  AttrService attrService;

  @Resource
  WareFeignService wareFeignService;

  @Resource
  SearchFeignService searchFeignService;

  @Override
  public PageUtils queryPage(Map<String, Object> params) {
    IPage<SpuInfoEntity> page = this.page(
      new Query<SpuInfoEntity>().getPage(params),
      new QueryWrapper<>()
    );

    return new PageUtils(page);
  }

  /**
   * 商品上架
   *
   * @param spuId
   */
  @Override
  @GlobalTransactional(rollbackFor = Exception.class)
  public void up(Long spuId) {
    //1、查处当前spuId对应的所有sku信息，品牌的名字
    List<SkuInfoEntity> skus = skuInfoService.getSkuBySpuId(spuId);

    List<Long> skuIdList = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());

    //TODO 4、查询当前sku的所有可以被用来检索的规格属性
    List<ProductAttrValueEntity> baseAttrs = productAttrValueService.list(new QueryWrapper<ProductAttrValueEntity>()
      .eq("spu_id", spuId));
    List<Long> attrIds = baseAttrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
    List<Long> searchIds = attrService.selectSearchAttrIds(attrIds);
    Set<Long> ids = new HashSet<>(searchIds);
    //过滤
    List<SkuEsModel.Attr> searchAttrs = baseAttrs.stream()
      .filter(entity -> ids.contains(entity.getAttrId()))
      .map(entity -> {
      SkuEsModel.Attr attr = new SkuEsModel.Attr();
      //属性对拷贝
      BeanUtils.copyProperties(entity, attr);
      return attr;
    }).collect(Collectors.toList());

    //TODO 1、发送远程调用，库存系统是否有库存
    Map<Long, Boolean> stockMap = null;
    try {
      R<List<SkuHasStockVo>> r = wareFeignService.getSkuHasStock(skuIdList);
      TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {
      };
      stockMap = r.getData(typeReference).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
    } catch (Exception e) {
      log.error("库存服务查询异常,原因{}", e);
    }

    //2、封装每个sku的信息
    Map<Long, Boolean> finalStockMap = stockMap;
    List<SkuEsModel> upProducts = skus.stream().map(sku -> {
      //组装需要的数据
      SkuEsModel esModel = new SkuEsModel();
      BeanUtils.copyProperties(sku, esModel);
      //skuPrice,skuImg
      esModel.setSkuPrice(sku.getPrice());
      esModel.setSkuImg(sku.getSkuDefaultImg());
      //hasStock,hotScore
      //设置库存信息
      esModel.setHasStock(finalStockMap != null && finalStockMap.get(sku.getSkuId()));

      //TODO 2、热度评分
      esModel.setHotScore(0L);
      //TODO 3、查询品牌和分类的名字信息
      BrandEntity brand = brandService.getById(esModel.getBrandId());
      esModel.setBrandName(brand.getName());
      esModel.setBrandImg(brand.getLogo());
      esModel.setAttrs(searchAttrs);
      CategoryEntity category = categoryService.getById(esModel.getCatalogId());
      esModel.setCatalogName(category.getName());
      return esModel;
    }).collect(Collectors.toList());
    //TODO 5、将数据发送给gulimall-search进行保存：
    R r = searchFeignService.productStatusUp(upProducts);
    if (r.getCode() == 0) {
      log.debug("elasticsearch save success");
      //调用成功
      //TODO 6、修改spu状态
      baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
    } else {
      log.debug("elasticsearch save fail");
      //调用失败
      //TODO 7、重复调用？接口幂等性、重试机制
    }
  }

}
